package com.gaofans.vertx.boot.web.config;

import com.gaofans.vertx.boot.common.config.VertxAutoConfig;
import com.gaofans.vertx.boot.common.verticle.VerticleInstanceScope;
import com.gaofans.vertx.boot.web.annotation.HttpHandler;
import com.gaofans.vertx.boot.web.exception.AnnotationExceptionHandlerDiscoverer;
import com.gaofans.vertx.boot.web.exception.ExceptionHandlerDiscoverer;
import com.gaofans.vertx.boot.web.exception.RouterExceptionConfigurer;
import com.gaofans.vertx.boot.web.handler.DefaultHttpHandlerDiscoverer;
import com.gaofans.vertx.boot.web.handler.HttpHandlerDiscoverer;
import com.gaofans.vertx.boot.web.handler.RouterHandlerConfigurer;
import com.gaofans.vertx.boot.web.route.DefaultRouteDiscoverer;
import com.gaofans.vertx.boot.web.route.RouterConfigurer;
import com.gaofans.vertx.boot.web.route.RouterExtConfigurer;
import com.gaofans.vertx.boot.web.server.HttpServerDeploymentOptionsBuilder;
import com.gaofans.vertx.boot.web.server.HttpServerResultHandlerBuilder;
import com.gaofans.vertx.boot.web.utils.HttpHandlerOrder;
import com.gaofans.vertx.boot.web.utils.WebConstant;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;

/**
 * web 服务器的配置
 * @author GaoFans
 */
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(VertxAutoConfig.class)
public class VertxWebAutoConfig {

    @Bean
    @ConfigurationProperties(WebConstant.VERTX_WEB_PREFIX)
    public HttpServerOptions httpServerOptions(){
        return new HttpServerOptions();
    }

    @Bean
    public DefaultRouteDiscoverer annotationRouteDiscoverer(){
        return new DefaultRouteDiscoverer();
    }

    @Bean
    @ConfigurationProperties(WebConstant.VERTX_WEB_OPTION_PREFIX)
    public DeploymentOptions httpDeploymentOptions(){
        return new DeploymentOptions();
    }

    @Bean
    public HttpServerDeploymentOptionsBuilder httpServerDeploymentOptionsBuilder(
            @Qualifier("httpDeploymentOptions") DeploymentOptions options){
        return new HttpServerDeploymentOptionsBuilder(options);
    }

    @Bean
    public HttpServerResultHandlerBuilder httpServerResultHandlerBuilder(){
        return new HttpServerResultHandlerBuilder();
    }

    @Bean
    public HttpHandlerDiscoverer httpHandlerDiscoverer(){
        return new DefaultHttpHandlerDiscoverer();
    }

    @Bean
    public ExceptionHandlerDiscoverer exceptionHandlerDiscoverer(){
        return new AnnotationExceptionHandlerDiscoverer();
    }

    @Bean
    public RouterConfigurer routerHandlerConfigurer(HttpHandlerDiscoverer httpHandlerDiscoverer){
        return new RouterHandlerConfigurer(httpHandlerDiscoverer);
    }

    @Bean
    public RouterConfigurer routerExceptionConfigurer(ExceptionHandlerDiscoverer exceptionHandlerDiscoverer){
        return new RouterExceptionConfigurer(exceptionHandlerDiscoverer);
    }

    @Bean
    @ConfigurationProperties(prefix = WebConstant.VERTX_WEB_REQUEST_BODY_BODY_PREFIX)
    public RequestBodyProperties requestBodyProperties(){
        return new RequestBodyProperties();
    }

    @HttpHandler(order = HttpHandlerOrder.BODY_CREATE_HANDLER)
    public Handler<RoutingContext> requestBodyHandler(RequestBodyProperties properties){
        return BodyHandler.create()
                .setBodyLimit(properties.getBodyLimit())
                .setDeleteUploadedFilesOnEnd(properties.isDeleteUploadedFilesOnEnd())
                .setHandleFileUploads(properties.isHandleFileUploads())
                .setPreallocateBodyBuffer(properties.isPreallocateBodyBuffer())
                .setUploadsDirectory(properties.getUploadsDirectory())
                .setMergeFormAttributes(properties.isMergeFormAttributes());
    }

    @ConfigurationProperties(prefix = WebConstant.VERTX_WEB_LOGGER_PREFIX)
    @ConditionalOnProperty(prefix = WebConstant.VERTX_WEB_LOGGER_PREFIX,name = "open",havingValue = "true")
    @Bean
    public WebLoggerProperties webLoggerProperties(){
        return new WebLoggerProperties();
    }

    @Bean
    @ConditionalOnBean(WebLoggerProperties.class)
    public RouterExtConfigurer loggerRouterExtConfigurer(WebLoggerProperties properties){
        return router -> router.route().order(HttpHandlerOrder.LOGGER_HANDLER).handler(LoggerHandler.create(properties.isImmediate(),properties.getFormat()));
    }

    @Bean
    public RouterExtConfigurer faviconHandler(){
        return router -> router.route().order(HttpHandlerOrder.FAVICON_HANDLER).handler(FaviconHandler.create());
    }

    @Bean
    @Lazy
    @Scope(VerticleInstanceScope.VERTICLE_INSTANCE_NAME)
    public ErrorHandler errorHandler(){
        return ErrorHandler.create();
    }

    @HttpHandler(order = HttpHandlerOrder.RESPONSE_BODY_HANDLER)
    public Handler<RoutingContext> responseContentTypeHandler(){
        return ResponseContentTypeHandler.create();
    }


}
